package com.jiangli.utils.Sreach;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

/**
 * 通用索引构建服务
 * 支持为任意实体类构建Redis倒排索引
 *
 * @param <T> 实体类类型
 * @param <ID> 实体ID类型
 */
@Component(value = "GenericIndex")
public class GenericIndexService<T, ID> {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 为单个实体构建索引
     *
     * @param entity 实体对象
     * @param idGetter 从实体中获取ID的函数
     * @param infoKeyPrefix 实体详情缓存的键前缀
     * @param indexKeyPrefix 倒排索引的键前缀
     * @param keywordsGetter 从实体中获取关键词列表的函数
     * @param expireHours 缓存过期时间（小时）
     */
    public void buildIndex(
            T entity,
            Function<T, ID> idGetter,
            String infoKeyPrefix,
            String indexKeyPrefix,
            Function<T, List<String>> keywordsGetter,
            int expireHours) {

        // 1. 获取实体ID
        ID entityId = idGetter.apply(entity);
        if (entityId == null) {
            throw new IllegalArgumentException("实体ID不能为空");
        }
        String idStr = entityId.toString();

        // 2. 缓存实体详情（JSON格式）
        String entityJson = JSON.toJSONString(entity);
        stringRedisTemplate.opsForValue().set(
                infoKeyPrefix + idStr,
                entityJson,
                expireHours,
                TimeUnit.HOURS
        );

        // 3. 获取并处理关键词
        List<String> keywords = keywordsGetter.apply(entity);
        if (CollectionUtils.isEmpty(keywords)) {
            return;
        }

        // 4. 构建倒排索引（关键词→实体ID）
        for (String keyword : keywords) {
            if (keyword != null && !keyword.trim().isEmpty()) {
                stringRedisTemplate.opsForSet().add(indexKeyPrefix + keyword.trim(), idStr);
            }
        }
    }

    /**
     * 批量为实体构建索引
     *
     * @param entities 实体列表
     * @param idGetter 从实体中获取ID的函数
     * @param infoKeyPrefix 实体详情缓存的键前缀
     * @param indexKeyPrefix 倒排索引的键前缀
     * @param keywordsGetter 从实体中获取关键词列表的函数
     * @param expireHours 缓存过期时间（小时）
     */
    public void batchBuildIndex(
            List<T> entities,
            Function<T, ID> idGetter,
            String infoKeyPrefix,
            String indexKeyPrefix,
            Function<T, List<String>> keywordsGetter,
            int expireHours) {

        if (CollectionUtils.isEmpty(entities)) {
            return;
        }

        // 批量处理每个实体
        entities.forEach(entity ->
                buildIndex(entity, idGetter, infoKeyPrefix, indexKeyPrefix, keywordsGetter, expireHours)
        );
    }

    /**
     * 删除实体的索引
     *
     * @param entityId 实体ID
     * @param infoKeyPrefix 实体详情缓存的键前缀
     */
    public void deleteIndex(ID entityId, String infoKeyPrefix) {
        if (entityId == null) {
            return;
        }
        // 删除实体详情缓存
        stringRedisTemplate.delete(infoKeyPrefix + entityId.toString());

        // 注意：倒排索引的删除需要额外记录实体关联的关键词，此处简化处理
    }

    /**
     * 根据关键词查询实体ID
     */
    public Set<String> queryEntityIds(String indexKeyPrefix, String keyword) {
        return stringRedisTemplate.opsForSet().members(indexKeyPrefix + keyword);
    }

    /**
     * 从缓存获取实体
     */
    public T getEntityFromCache(String infoKeyPrefix, ID entityId, Class<T> entityClass) {
        if (entityId == null) {
            return null;
        }
        String json = stringRedisTemplate.opsForValue().get(infoKeyPrefix + entityId.toString());
        return json != null ? JSON.parseObject(json, entityClass) : null;
    }
}
